package ru.ipo.dces.plugins.admin.components;


import ru.ipo.dces.clientservercommunication.PluginSide;
import ru.ipo.dces.plugins.admin.PluginsManagementPluginV2;
import ru.ipo.dces.plugins.admin.beans.PluginState;
import ru.ipo.dces.plugins.admin.resources.ImageResources;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

public class PluginsTable extends JTable {

    private AbstractTableModel model = new PluginsAbstractTableModel();
    private static Map<String, PluginState> pluginStates;
    private HashSet<ActionListener> selectionListeners = new HashSet<ActionListener>();
    private TableRowSorter<AbstractTableModel> sorter = new TableRowSorter<AbstractTableModel>(model);
    private static final TableCellRenderer stateRenderer = new TableCellRenderer() {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                       boolean hasFocus, int row, int column) {
            JLabel label = new JLabel();
            label.setOpaque(true);
            label.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
            label.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
            label.setIcon(new MultipleIcon((PluginState) value));
            return label;
        }
    };

    private static final TableCellRenderer typeRenderer = new TableCellRenderer() {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                       boolean hasFocus, int row, int column) {
            JLabel label = new JLabel((String) value, SwingConstants.CENTER);
            label.setOpaque(true);
            label.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
            label.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
            return label;
        }
    };

    private static final TableCellRenderer aliasRenderer = new TableCellRenderer() {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                       boolean hasFocus, int row, int column) {
            @SuppressWarnings({"SuspiciousMethodCalls"})
            PluginState plugin = PluginsTable.pluginStates.get(value);
            JLabel label = new JLabel(plugin.getAlias(), SwingConstants.LEFT);
            label.setOpaque(true);
            label.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
            label.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
            if (plugin.getPluginSide() == PluginSide.Server)
                label.setForeground(Color.BLUE);
            if (plugin.getPluginSide() == PluginSide.Client)
                label.setForeground(Color.GREEN.darker().darker());
            label.setText(plugin.getAlias());
            return label;
        }
    };

    public PluginsTable(PluginsManagementPluginV2 parentPlugin) {
        super();
        setModel(model);
        getTableHeader().setReorderingAllowed(false);

        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent listSelectionEvent) {
                if (!listSelectionEvent.getValueIsAdjusting())
                    for (ActionListener listener : selectionListeners)
                        listener.actionPerformed(new ActionEvent(this, 0, null));
            }
        });
        setRowSorter(sorter);
        setRowHeight(ImageResources.SERVER_IMAGE.getIconHeight() + 5);
        pluginStates = parentPlugin.pluginsStates.getPluginsStates();
    }

    public void update() {
//        int selectedRow = getSelectedRow();
        model.fireTableStructureChanged();
        /*if (selectedRow != -1) {
            setRowSelectionInterval(selectedRow, selectedRow);
            for (ActionListener listener : selectionListeners)
                listener.actionPerformed(new ActionEvent(this, 0, null));
        }*/
    }

    public void addSelectionListener(ActionListener listener) {
        selectionListeners.add(listener);
    }

    public class PluginsAbstractTableModel extends AbstractTableModel {

        @Override
        public int getRowCount() {
            if (pluginStates == null)
                return 0;
            return pluginStates.size();
        }

        @Override
        public int getColumnCount() {
            return 4;
        }

        @Override
        public String getColumnName(int column) {
            switch (column) {
                case 0:
                    return "Название";
                case 1:
                    return "Тип";
                case 2:
                    return "Описание";
                case 3:
                    return "Статус";
            }
            return "";
        }

        @Override
        public Object getValueAt(int row, int column) {
            int i = 0;
            PluginState pluginState = null;
            for (Map.Entry<String, PluginState> entry : pluginStates.entrySet()) {
                if (row == i) {
                    pluginState = entry.getValue();
                    break;
                }
                i++;
            }
            if (pluginState == null)
                return null;

            switch (column) {
                case 0:
                    return pluginState.getAlias();    // Process in cell renderer
                case 1:
                    if (pluginState.getPluginSide() == null)
                        return "";
                    if (pluginState.getPluginSide() == PluginSide.Server)
                        return "Серверный";
                    else
                        return "Клиентский";
                case 2:
                    return pluginState.getDescription();
                case 3:
                    return pluginState;    // Process in cell renderer
            }
            return null;
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return column == 2;
        }

        @Override
        public void fireTableStructureChanged() {
            super.fireTableStructureChanged();
            sorter.sort();
            PluginsTable.this.getColumnModel().getColumn(0).setCellRenderer(aliasRenderer);
            PluginsTable.this.getColumnModel().getColumn(1).setCellRenderer(typeRenderer);
            PluginsTable.this.getColumnModel().getColumn(3).setCellRenderer(stateRenderer);
            int stringWidth = Math.round((float) PluginsTable.this.getFontMetrics(PluginsTable.this.getFont()).
                    getStringBounds("Клиентский", PluginsTable.this.getGraphics()).getWidth());
            getColumnModel().getColumn(1).setMinWidth(stringWidth + 10);
            getColumnModel().getColumn(1).setMaxWidth(stringWidth + 10);
            getColumnModel().getColumn(3).setMaxWidth(ImageResources.SERVER_IMAGE.getIconWidth() * 3 + 15);
            getColumnModel().getColumn(3).setMinWidth(ImageResources.SERVER_IMAGE.getIconWidth() * 3 + 15);
        }
    }

    private static class MultipleIcon implements Icon {

        private PluginState plugin;
        private int separatorGap = 5;

        public MultipleIcon(PluginState plugin) {
            this.plugin = plugin;
        }

        @Override
        public void paintIcon(Component component, Graphics graphics, int x, int y) {
            int iconWidth = ImageResources.SERVER_IMAGE.getIconWidth();
            if (plugin.isAvailableOnServer()) {
                ImageResources.SERVER_IMAGE.paintIcon(component, graphics, x, y);
                if (plugin.isAvailableInDownloads()) {
                    ImageResources.DOWNLOAD_IMAGE.paintIcon(component, graphics, x + iconWidth + separatorGap, y);
                    if (plugin.isAvailableInUpdates())
                        ImageResources.UPLOAD_IMAGE.paintIcon(component, graphics, x + 2 * iconWidth + 2 * separatorGap, y);
                } else if (plugin.isAvailableInUpdates())
                    ImageResources.UPLOAD_IMAGE.paintIcon(component, graphics, x + iconWidth + separatorGap, y);
            } else if (plugin.isAvailableInDownloads()) {
                ImageResources.DOWNLOAD_IMAGE.paintIcon(component, graphics, x, y);
                if (plugin.isAvailableInUpdates())
                    ImageResources.UPLOAD_IMAGE.paintIcon(component, graphics, x + iconWidth + separatorGap, y);
            } else if (plugin.isAvailableInUpdates())
                ImageResources.UPLOAD_IMAGE.paintIcon(component, graphics, x, y);
        }

        @Override
        public int getIconWidth() {
            int width = 0;
            if (plugin.isAvailableOnServer())
                width++;
            if (plugin.isAvailableInDownloads())
                width++;
            if (plugin.isAvailableInUpdates())
                width++;
            if (width == 0)
                return 0;
            return ImageResources.SERVER_IMAGE.getIconWidth() * width + separatorGap * (width - 1);
        }

        @Override
        public int getIconHeight() {
            return ImageResources.SERVER_IMAGE.getIconHeight();
        }
    }
}
